package com.snapan.util;

import org.springframework.web.multipart.MultipartFile;

import java.io.*;

/**
 * 简化的文件处理工具类
 * <p>
 * 提供文件上传、分片处理、文件合并及删除等常用文件操作功能，
 * 适用于处理Web应用中的文件上传场景，特别是大文件分片上传需求。
 * </p>
 */
public class FileUtils {
//hello
    /**
     * 生成存储文件名
     * <p>
     * 根据原始文件名生成唯一的存储文件名，规则为：当前时间戳 + 原始文件扩展名，
     * 避免文件名冲突问题。如果原始文件名没有扩展名，则只返回时间戳。
     * </p>
     *
     * @param originalFileName 原始文件名，可能包含扩展名
     * @return 生成的唯一存储文件名
     */
    public static String generateStorageFileName(String originalFileName) {
        String extension = "";
        // 提取文件扩展名（如果存在）
        if (originalFileName != null && originalFileName.lastIndexOf('.') != -1) {
            extension = originalFileName.substring(originalFileName.lastIndexOf('.'));
        }
        // 时间戳保证唯一性，拼接扩展名
        return System.currentTimeMillis() + extension;
    }

    /**
     * 生成分片文件名
     * <p>
     * 为文件分片生成标准格式的文件名，规则为："chunk_" + 文件唯一标识 + "_" + 分片序号 + ".tmp"，
     * 便于后续识别和合并分片文件。
     * </p>
     *
     * @param identifier  文件的唯一标识符，用于关联同一个文件的所有分片
     * @param chunkNumber 分片序号，从0或1开始的整数
     * @return 生成的分片文件名
     */
    public static String generateChunkFileName(String identifier, int chunkNumber) {
        return "chunk_" + identifier + "_" + chunkNumber + ".tmp";
    }

    /**
     * 保存分片文件
     * <p>
     * 将上传的分片文件保存到指定目录，若目录不存在则自动创建。
     * 使用Spring的MultipartFile.transferTo()方法实现高效文件写入。
     * </p>
     *
     * @param chunk        分片文件对象，由Spring MVC上传解析得到
     * @param chunkDir     分片文件存储目录
     * @param chunkFileName 分片文件名，建议通过generateChunkFileName()方法生成
     * @return 保存后的分片文件完整路径
     * @throws IOException 当文件写入失败或目录创建失败时抛出
     */
    public static String saveChunkFile(MultipartFile chunk, String chunkDir, String chunkFileName) throws IOException {
        // 创建分片存储目录（如果不存在）
        File dir = new File(chunkDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 构建分片文件完整路径
        String chunkFilePath = chunkDir + File.separator + chunkFileName;
        File chunkFile = new File(chunkFilePath);
        // 保存分片文件
        chunk.transferTo(chunkFile);
        return chunkFilePath;
    }

    /**
     * 合并分片文件
     * <p>
     * 将多个分片文件按顺序合并为一个完整的文件。合并过程中会校验每个分片是否存在，
     * 若任何分片缺失则抛出运行时异常。合并完成后返回目标文件路径。
     * </p>
     *
     * @param chunkFilePaths 分片文件路径数组，需保证按正确顺序排列
     * @param outputPath     合并后的目标文件完整路径
     * @return 合并后的目标文件路径
     * @throws IOException 当文件读取、写入失败或目标目录创建失败时抛出
     * @throws RuntimeException 当任何分片文件不存在时抛出
     */
    public static String mergeChunkFiles(String[] chunkFilePaths, String outputPath) throws IOException {
        File outputFile = new File(outputPath);
        // 创建目标文件的父目录（如果不存在）
        File parentDir = outputFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        // 记录总写入字节数（用于调试和校验）
        long totalBytesWritten = 0;
        // 使用try-with-resources自动关闭输出流
        try (FileOutputStream fos = new FileOutputStream(outputFile)) {
            // 按顺序读取每个分片并写入目标文件
            for (int i = 0; i < chunkFilePaths.length; i++) {
                String chunkFilePath = chunkFilePaths[i];
                File chunkFile = new File(chunkFilePath);

                // 检查分片文件是否存在
                if (chunkFile.exists()) {
                    // 使用try-with-resources自动关闭输入流
                    try (FileInputStream fis = new FileInputStream(chunkFile)) {
                        byte[] buffer = new byte[8192]; // 8KB缓冲区
                        int bytesRead;
                        long chunkBytesWritten = 0;
                        // 读取分片内容并写入目标文件
                        while ((bytesRead = fis.read(buffer)) != -1) {
                            fos.write(buffer, 0, bytesRead);
                            chunkBytesWritten += bytesRead;
                        }
                        totalBytesWritten += chunkBytesWritten;
                    }
                } else {
                    // 分片缺失时抛出异常
                    throw new RuntimeException("分片文件不存在: " + chunkFilePath);
                }
            }
        }

        return outputPath;
    }

    /**
     * 删除文件
     * <p>
     * 删除指定路径的文件，若文件不存在或删除失败则返回false，删除成功返回true。
     * 注意：此方法只能删除文件，不能删除目录。
     * </p>
     *
     * @param filePath 要删除的文件路径
     * @return 若文件删除成功则返回true，否则返回false
     */
    public static boolean deleteFile(String filePath) {
        return new File(filePath).delete();
    }
}